
import random
import re
from playwright.sync_api import Playwright, sync_playwright, expect
import os
from process_amazon2 import human_like_scroll
from public_xue import array_to_string, get_filename_part, sleep
import time
import math
import traceback
import asyncio
import uuid
from random import randint
import datetime   
class miaoshou_auto(object):
    def __init__(self, textUpdateSignal):
        self.textUpdateSignal = textUpdateSignal
        self.currentpage=1
        
    def miaoshou_login(self,page):
        """修复线程问题"""
        try:
            # 添加捕获所有可能的异常
            try:
                page.goto("https://erp.91miaoshou.com/walmart/collect_box/items",timeout=2000)
                sleep(random.random()*0.5)
                if page.url.find("collect_box/items")==-1:
                    page.get_by_role("textbox", name="手机号/子账号/邮箱").click()
                    page.get_by_role("textbox", name="手机号/子账号/邮箱").click() 
                    page.get_by_role("textbox", name="手机号/子账号/邮箱").fill("KLMTX88")
                    page.get_by_role("textbox", name="手机号/子账号/邮箱").press("Tab")
                    page.get_by_role("textbox", name="密码").click() 
                    page.get_by_role("textbox", name="密码").fill("jane1025seller//@") 
                    page.get_by_role("button", name="立即登录").click()
                    page.get_by_label("关闭此对话框").first.click()
                    page.get_by_role("button", name="关闭此对话框").click()
                    page.get_by_placeholder("快速搜索功能").click()
                return True
            except Exception as e:
                traceback.print_exc()
                if "cannot switch to a different thread" in str(e):
                    # 如果是线程错误，重试或提供错误信息
                    print(f"线程切换错误，可能需要重启应用: {e}")
                raise  # 重新抛出以便调用者处理
        except Exception as e:
            print(f"妙手登录失败: {e}")
            traceback.print_exc()

            return False

    def get_upc_list(self,page, db_helper,upc_list_used):
        try:
            if upc_list_used and len(upc_list_used)>0:
                upcs=array_to_string(upc_list_used)
                sqlupc_update =f'update app_upc_xue set upload_at=now() where upc in ({upcs})'
                db_helper.execute(sqlupc_update)
            sqlupc='select * from app_upc_xue where upload_at is null'
            upc_list_result=db_helper.query_one(sqlupc)
            upc_list_no_used=[record['upc'] for record in upc_list_result]
            upc_list_used=[]
        except Exception as e:
            print(f"获取UPC列表失败: {e}")
            traceback.print_exc()
            return []
        return upc_list_no_used

    def miaoshou_process_upload(self,page, db_helper):
        """
        读取妙手ERP采集箱中的商品，对比数据库中的ASIN，选中匹配的商品
        
        Args:
            page: playwright页面对象
            db_helper: 数据库连接助手（用于检查ASIN是否存在）
        """
        self.upc_list_no_used=self.get_upc_list(page, db_helper,None)
        self.upc_list_used=[]

        sql = f"SELECT productid,keywords,detail1,detail2,detail3,detail4,detail5,weight FROM app_product_xue  where can_pubished=1 and uploadtowalmartdate is null   "
        result = db_helper.query_one(sql)
        self.asin_list = [record['productid'] for record in result]
        self.weight_list = [record['weight'] for record in result]
        self.keywords_list = [record['keywords'] for record in result]
        self.detail1_list = [record['detail1'] for record in result]
        self.detail2_list = [record['detail2'] for record in result]
        self.detail3_list = [record['detail3'] for record in result]
        self.detail4_list = [record['detail4'] for record in result]
        self.detail5_list = [record['detail5'] for record in result]
        self.detail_list = [self.detail1_list,self.detail2_list,self.detail3_list,self.detail4_list,self.detail5_list]

        
        print("开始读取采集箱商品信息...")
        
        # 确保页面已加载
        try:
            # page.goto("https://erp.91miaoshou.com/walmart/collect_box/items", timeout=6000)
            page.bring_to_front()
        except Exception as e:
            print(f"页面加载失败: {e}")
            traceback.print_exc()
        sleep(random.random()*0.5)
        print("采集箱页面加载完成")
        sleep(random.random())
        rowsnumber=0
        locator = page.locator('label').filter(has_text=re.compile(r'未发布 \(\d+\)'))
        try:
            if locator.count():
                locator.first.click()   
        except Exception as e:
            print(f"点击未发布失败: {e}")
            traceback.print_exc()
        if locator.count() > 0:
        # 获取第一个匹配元素的文本内容
            element_text = locator.first.text_content()
            # 使用正则表达式提取数字
            match = re.search(r'\d+', element_text)
            if match:
                number = match.group()
                print(f"未发布后面的数字是: {number}")
                rowsnumber=int(number)
            else:
                print("未找到匹配的数字")
        else:
            print("未找到匹配的元素")
        page.locator(".el-pagination__sizes .el-select").click()
        sleep(random.random()*0.2)

        # 选择指定条数
        items_selector = f".el-select-dropdown__item:has-text('10条/页')"
        if page.is_visible(items_selector):
            page.locator(items_selector).click()
            print(f"已设置每页显示 10 条商品")
         # 处理采集箱中的所有商品
        page.wait_for_selector(".jx-pro-virtual-table__row" )
        # 获取初始可见行数

        print(f"初始可见行数: {rowsnumber}")
        # 
         
        page.evaluate("window.scrollTo(0, document.body.scrollHeight);")
        sleep(random.random()*0.5)
        page.evaluate("window.scrollTo(0, 0);")
        timesleep=1500
        sleep(random.random()*0.1)

        # 滚动加载更多行并处理
        pagecount=10
        max_scroll_attempts = 30  # 防止无限循环
        scroll_attempts = 0
        uploaded_asins=[]
        results=[]
        
        total_pages=math.ceil(rowsnumber/pagecount)
        dealpages=total_pages
        self.currentpage=1
        for ix in range(1,dealpages):
            resultx=self.process_single_row(page, db_helper,ix+1,total_pages,rowsnumber)
            results.append(resultx)
        asins=[]
        self.upc_list_used=[]
        for result in results:
            if result and result['asins'] and len(result['asins'])>0:
                asins.extend(result['asins'])
                self.upc_list_used.extend(result['upc_list_used'])
        
        if results and len(asins)>0:
        # 批量选择后，设置价格，暂时批量0.95折
            asins_list= array_to_string(asins)
            # asins_list=asins_list[-1]
            sql_update=f'update app_product_xue set uploadtowalmartdate=now()  where productid in ({asins_list})'
            db_helper.execute(sql_update)
            sql_update=f'insert into sku_keywords_history(sku,keywords,opdate) values({asins_list},"uploadtowalmart",now())'
            db_helper.execute(sql_update)     
            upc_list_no_used=self.get_upc_list(page, db_helper,self.upc_list_used)
        print(f"完成处理！共读取 {rowsnumber} 行")       
        timesleep=500
    def process_single_row(self,page, db_helper,currentpage,total_pages,rowsnumber):
        timesleep=500
        asin=''
        print(2)
        processed_asin=[]
        startrow=1
        print(3)
        pagecount=10
        if currentpage<total_pages or rowsnumber==pagecount*total_pages:
            rowsnumber=pagecount
        else:
            rowsnumber=rowsnumber%pagecount
        if currentpage!=1 and currentpage!=total_pages:
            page.locator(f"//ul[@class='el-pager']/li[@class='number' and text()='{currentpage}']").click()
            sleep(random.random()*0.5)
        item_view_elements = page.query_selector_all('.vue-recycle-scroller__item-view')  
        print(f"找到 {len(item_view_elements)} 个 .vue-recycle-scroller__item-view 元素。") 

        for cindex,item_view in enumerate(item_view_elements):
            if len(item_view.text_content())>5:
                item_view.scroll_into_view_if_needed()
                sleep(random.random()*0.5)
                checkboxes = item_view.query_selector_all('input[type="checkbox"].el-checkbox__original')
                print(f"在当前 .vue-recycle-scroller__item-view 元素中找到 {len(checkboxes)} 个复选框。")
                for   checkbox in    checkboxes:
                    for retry in range(2):

                        try:
                                                        # 等待复选框可见
                            checkbox.wait_for_element_state('visible', timeout=5000)
                            # 等待复选框稳定
                            checkbox.wait_for_element_state('stable', timeout=5000)# 等待复选框可见并稳定
                            checkbox.check()

                            checkbox.wait_for(state='visible', timeout=5000)
                            checkbox.wait_for(state='stable', timeout=5000)
                            checkbox.check()
                            break
                        except Exception as e:
                            print(f"处理复选框时出错: {e}")
                # checkbox.uncheck()  
        for ixx in range( rowsnumber ):   
            try:
                item_view=item_view_elements[ixx]
                item_view.scroll_into_view_if_needed()
                sleep(random.random()*0.5)
                rowindex=ixx+1
                print(4)
                checkboxes = item_view.query_selector_all('input.el-checkbox__original[type="checkbox"]')
                sleep(random.random()*0.5)
                checkbox = item_view.query_selector('input[type="checkbox"].el-checkbox__original')
                for retry in range(2):

                    try:
                        # 等待复选框可见并稳定
                        checkbox.wait_for(state='visible', timeout=5000)
                        checkbox.wait_for(state='stable', timeout=5000)
                        checkbox.check()
                        break
                    except Exception as e:
                        print(f"处理复选框时出错: {e}")
                if checkbox:
                    # 选中复选框
                    checkbox.check()
                    print("复选框已选中")
                else:
                    print("未找到复选框")


                    # print(item_view.inner_html())
                # Process each row
                for item_view in item_view_elements:
                    try:
                        # Scroll row into view
                        item_view.scroll_into_view_if_needed()
                        sleep(random.random() * 0.5)

                        # Get checkbox and title for current row
                        checkbox = item_view.query_selector('input.el-checkbox__original[type="checkbox"][aria-hidden="false"]')
                        title_element = item_view.query_selector('.title-wrap.J_editGoodsTitle span')
                        
                        if checkbox and title_element:
                            title = title_element.text_content()
                            print(f"Processing product: {title}")
                            
                            # Check the checkbox if not already checked
                            if not checkbox.is_checked():
                                checkbox.check()
                                print(f"Checked checkbox for: {title}")
                            sleep(random.random() * 0.3)
                        else:
                            print("Could not find checkbox or title element in row")

                    except Exception as e:
                        print(f"Error processing row: {str(e)}")
                        traceback.print_exc()
                        continue



                if rowindex %10==0 and rowindex >= 10:
                    page.keyboard.press('Tab')
                    sleep(random.random()*0.2)
                    page.keyboard.press('ArrowDown')    
                    sleep(random.random()*0.2)
                row_selector = f"div:nth-child({rowindex}) > .jx-pro-virtual-table__row"
                print(rowindex,5)   
                if page.locator(row_selector).count() > 0:
                    print(f"第{rowindex}行已在DOM中，直接滚动")
                    # page.locator(row_selector).scroll_into_view_if_needed()
                    page.evaluate(f"""(selector) => {{
                            const element = document.querySelector(selector);
                            if (element) {{
                                element.scrollIntoView({{behavior: 'smooth', block: 'center'}});
                                return true;
                            }}
                            return false;
                        }}""", row_selector)
                    sleep(random.random())
                    page.wait_for_timeout(timesleep)   
                sleep(random.random()*0.5)
                print(f'第{rowindex}行，开始读取类目，标题')    

                title=''
                category_element = page.query_selector('.jx-pro-tag.category-tag span[title]')

                if category_element:
                    # 获取 title 属性值
                    category_title = category_element.get_attribute('title').replace('>','_')
                title=''
                title_element = page.query_selector('.title-wrap.J_editGoodsTitle span')
                if title_element:
                    title = title_element.text_content()

                if category_title=='':
                    strtip=f'第{rowindex}行,{title},类目为空，跳过不处理'
                    self.textUpdateSignal.emit(strtip)
                    continue
                print(rowindex,7)    
                for index, checkbox in enumerate(checkboxes, start=1):
                    if index == 7:
                        if not checkbox.is_checked():
                            checkbox.check()
                    else:
                        if checkbox.is_checked():
                            checkbox.uncheck()
                print(rowindex,8)   
                element = page.query_selector('.goods-info-item:has-text("货源：") a')
                amazon_url = element.get_attribute('href') if element else ''
                sleep(random.random()*0.1)
                if not amazon_url:
                    self.textUpdateSignal.emit(f"第{rowindex}行,{title},没有找到亚马逊链接")
                    continue
                asin_match = re.search(r"/dp/([A-Z0-9]{10})", amazon_url)
                print(rowindex,10)    
                if not asin_match:
                    self.textUpdateSignal.emit(f"第{rowindex}行,{title},无法从链接提取ASIN: {amazon_url}")
                    continue
                asin = asin_match.group(1)
                asinindex=-1
                is_in_database = False
                if asin in self.asin_list:
                    is_in_database = True
                    asinindex=self.asin_list.index(asin)
                print(rowindex,12)    
                print('asin在asinlist中位置：',asinindex,'，当前行：',rowindex,f"提取到ASIN: {asin}",f"category_text: {category_title}",f"title: {title}")       
                if asin in self.asin_list:
                    all_checkboxes = page.locator("div.jx-pro-virtual-table__row > div > .el-checkbox > .el-checkbox__input > .el-checkbox__inner")
                    total_rows = all_checkboxes.count()
                    for i in range(total_rows):
                        checkbox = all_checkboxes.nth(i)
                        if checkbox.is_checked():
                            checkbox.uncheck()
                    checkbox =page.locator(f"div:nth-child({rowindex}) > .jx-pro-virtual-table__row > div > .el-checkbox > .el-checkbox__input > .el-checkbox__inner") 
                    checkbox.check()
                    print(rowindex,14)    
                    sleep(random.random()*random.randint(2,3))
                    page.get_by_role("button", name="设置售价").click()
                    page.get_by_role("radio", name="使用公式：").click()
                    page.get_by_placeholder("倍数").click()
                    page.get_by_placeholder("倍数").fill("0.98")
                    page.get_by_role("button", name="应用至选中").click()
                    page.get_by_role("button", name="关闭", exact=True).click()
                    sleep(random.random()*0.1)
                    page.evaluate(f"""(selector) => {{
                            const element = document.querySelector(selector);
                            if (element) {{
                                element.scrollIntoView({{behavior: 'smooth', block: 'center'}});
                                return true;
                            }}
                            return false;
                        }}""", row_selector)
                    
                    if checkbox:
                        checkbox.check()
                    page.get_by_role("button", name="引用模板").click()
                    sleep(random.random()*0.1)
                    print(rowindex,15)      
                    page.get_by_placeholder("请选择模板").click()
                    sleep(random.random()*0.1)
                    template_name=f"{category_title}_auto"
                    elements_template = page.get_by_text(template_name).all()
                    if len(elements_template) == 1:
                        page.get_by_text(template_name).click()
                    else:   
                        self.textUpdateSignal.emit(f"{asin},{title},妙手ERP，没有找到模板：{template_name}")
                        page.get_by_text("批量引用模板", exact=True).first.click()
                        # page.locator("//button[@data-v-2c9d4f7a and .//span[text()='取消']]").click()
                        sleep(random.random()*1.1)
                        page.get_by_role("button", name="取消").first.click()
                        continue
                    print(rowindex,16)    
                    if len(elements_template) == 1:
                        sleep(random.random()*1.1)
                        page.get_by_role("button", name="应用至选中").click()
                        sleep(random.random()*1.1)
                        page.get_by_role("button", name="关闭", exact=True).click()
                    sleep(random.random()*1.1)
                    page.locator(f"div:nth-child({rowindex}) > .jx-pro-virtual-table__row > div:nth-child(8) > .operate-box > .el-button-group > button").first.click()                
                    sleep(random.random()*0.1)
                    page.locator("li").filter(has_text="基本信息").locator("div").click()
                    textareas = page.locator('textarea.el-textarea__inner')
                    playwright_count = textareas.count()
                    print(rowindex,17)    
                    for i in range(5):
                        if self.detail_list[i][asinindex]:
                            textareas.nth(i+1).fill(self.detail_list[i][asinindex])
                    page.locator("li").filter(has_text="其他信息").locator("div").click()
                    sleep(random.random()*0.6)
                    print(rowindex,18)    
                    page.locator(".other-info-box > div > .el-form-item__content > .edit-field-content > .jx-pro-input > .el-input__inner").first.click()
                    sleep(random.random()*0.1)
                    page.locator(".other-info-box > div > .el-form-item__content > .edit-field-content > .jx-pro-input > .el-input__inner").first.fill("MCKEE")
                    sleep(random.random()*0.1)
                    page.locator(".other-info-box > div > .el-form-item__content > .edit-field-content > .jx-pro-input > .el-input__inner").first.press("Tab")
                    sleep(random.random()*0.1)
                    random_uuid = uuid.uuid4()
                    # 获取 UUID 的前 8 个字符
                    part_of_uuid = str(random_uuid)[:8]
                    print(part_of_uuid)
                    print(rowindex,19)                         
                    sleep(random.random()*0.1)
                    page.locator("div:nth-child(5) > .el-form-item__content > .edit-field-content > .jx-pro-input > .el-input__inner").click()
                    sleep(random.random()*0.1)
                    if self.weight_list[asinindex] and self.weight_list[asinindex]!='' and self.weight_list[asinindex]!=None:
                        page.locator("div:nth-child(5) > .el-form-item__content > .edit-field-content > .jx-pro-input > .el-input__inner").fill(str(round(float(self.weight_list[asinindex] *2.22),2)))   
                    sleep(random.random()*0.1)
                    page.locator("div:nth-child(7) > .el-form-item__content > .edit-field-content > .el-select > .el-input > .el-input__inner").first.click()
                    sleep(random.random()*0.1)
                    # page.get_by_role("tablist").get_by_text("1").click()
                    print(rowindex,20)    
                    page.get_by_text("销售属性", exact=True).click()
                    lastlen=0
                    input_elements = page.locator('input.el-input__inner[minlength="1"][maxlength="14"]')
                    while lastlen!=input_elements.count():
                        lastlen=input_elements.count()
                        input_elements.nth(input_elements.count()-1 ).scroll_into_view_if_needed()
                        sleep(random.random()*0.6)                        
                        input_elements = page.locator('input.el-input__inner[minlength="1"][maxlength="14"]')
                        sleep(random.random()*0.6)
                    count = input_elements.count()
                    print(f"销售属性输入框数量: {count}")
                    # 批量获取，输入UPC
                    print(rowindex,21)    
                    for i in range(count):
                        sleep(random.random()*0.1)
                        current_input = input_elements.nth(i)
                        current_input.scroll_into_view_if_needed()
                        orginupc=current_input.input_value()
                        print(f"原始UPC: {orginupc}")
                        current_input.fill('')
                        upc=''
                        current_upc=''
                        if not  self.upc_list_no_used:
                            self.upc_list_no_used=self.get_upc_list(page, db_helper,self.upc_list_used)
                            self.upc_list_used=[]
                        if self.upc_list_no_used:
                            current_upc=self.upc_list_no_used.pop(0)
                        print(f"当前UPC: {current_upc}")
                        self.upc_list_used.append(current_upc)
                        upc=current_upc
                        current_input.type(upc)
                        print(rowindex,22)    

                        sleep(random.random() * 0.5)
                    page.get_by_role("button", name="保存修改").click()
                    sleep(random.random()*0.1)
                    page.get_by_role("button", name="取消").first.click()   
                    sleep(random.random()*0.1)
                    print(rowindex,23)           
                    if page.locator("button.el-button.el-button--default.el-button--small.el-button--primary").count() > 0:
                        page.locator("button.el-button.el-button--default.el-button--small.el-button--primary").click()
                    sleep(random.random()*0.1)
                    checkbox.check()

                    page.locator(f"div:nth-child({rowindex}) > .jx-pro-virtual-table__row > div:nth-child(8) > .operate-box > .el-button-group > button:nth-child(4)").click()
                    page.wait_for_timeout(500)
                    print(rowindex,25)    

                    page.locator('//textarea[@class="el-textarea__inner"]').fill(f"{datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}，你好，这是程序自动完善产品信息的。")
                    page.get_by_role("button", name="确定").click()
                    print(f"已成功为第{rowindex}行,{asin},{title}添加备注内容")
                    page.locator(f"div:nth-child({rowindex}) > .jx-pro-virtual-table__row > div:nth-child(8) > .operate-box > .operate-mark").click()
                    print(rowindex,26)    

                    processed_asin.append(asin)
            except Exception as e:
                traceback.print_exc()
                continue
            

        return {'asins':processed_asin,'upc_list_used':self.upc_list_used}
    # 首先处理当前可见的行
        # for rowindex in range(rowsnumber):
        #     if process_multi_row(rowindex+1):
        #         selected_count += 1
        
         
     
   
   
    def upload_network_image_without_js(self, page, image_url):
        """使用纯Playwright API上传网络图片并处理确认操作"""
        try:
            print("开始添加网络图片...")
            
            # 1. 点击添加图片按钮
            add_image_selector = ".image-item.forbid .add-image-box"
            page.locator(add_image_selector).click()
            sleep(random.random()*0.5)  # 等待弹框出现
            
            # 2. 检查是否有网络图片选项并点击
            network_image_options = [
                "text=网络图片",                  # 文本匹配
                ".el-tabs__item:has-text('网络图片')",  # 选项卡
                "button:has-text('网络图片')",    # 按钮形式
                ".image-upload-method:has-text('网络图片')"  # 可能的自定义类
            ]
            
            network_btn_found = False
            for selector in network_image_options:
                if page.locator(selector).count() > 0:
                    try:
                        page.locator(selector).click()
                        network_btn_found = True
                        print(f"找到并点击了网络图片选项: {selector}")
                        break
                    except Exception as e:
                        print(f"尝试点击 {selector} 失败: {str(e)}")
                        continue
            
            if not network_btn_found:
                print("警告: 未找到网络图片选项，尝试查找URL输入框")
            
            # 3. 尝试找到URL输入框并填写
            url_input_options = [
                "input[placeholder='请输入图片URL']",
                "input[type='url']",
                ".el-input__inner:visible",  # 尝试所有可见的输入框
                ".url-input input"
            ]
            
            url_input_found = False
            for selector in url_input_options:
                url_input = page.locator(selector)
                if url_input.count() > 0:
                    try:
                        url_input.first.fill(image_url)
                        url_input_found = True
                        print(f"找到并填写了URL输入框: {selector}")
                        break
                    except Exception as e:
                        print(f"尝试填写 {selector} 失败: {str(e)}")
                        continue
            
            if not url_input_found:
                print("错误: 未找到URL输入框，无法填写图片地址")
                return False
            
            # 4. 点击确定按钮
            confirm_button_options = [
                "button:has-text('确定')",
                ".el-button--primary:has-text('确定')",
                ".dialog-footer button.el-button--primary",
                ".dialog-action .confirm"
            ]
            
            sleep(random.random()*0.3)  # 等待确认按钮可点击
            
            confirm_btn_found = False
            for selector in confirm_button_options:
                confirm_btn = page.locator(selector)
                if confirm_btn.count() > 0 and confirm_btn.is_visible():
                    try:
                        confirm_btn.click()
                        confirm_btn_found = True
                        print(f"找到并点击了确定按钮: {selector}")
                        break
                    except Exception as e:
                        print(f"尝试点击 {selector} 失败: {str(e)}")
                        continue
            
            if not confirm_btn_found:
                print("警告: 未找到确定按钮，尝试按Enter键提交")
                page.keyboard.press("Enter")
            
            # 5. 等待图片上传完成
            sleep(random.random()*1.5)
            
            # 6. 检查是否上传成功
            uploaded_images = page.locator(".image-item:not(.forbid)")
            count = uploaded_images.count()
            
            if count > 0:
                print(f"图片上传成功，当前共有 {count} 张图片")
                return True
            else:
                print("图片上传可能失败，未检测到新图片")
                return False
            
        except Exception as e:
            print(f"上传图片过程中出错: {str(e)}")
            traceback.print_exc()
            return False
   
    def check_add_image_element_exists(self, page):
        """
        检查页面上是否存在添加图片的元素
        
        Args:
            page: Playwright页面对象
        
        Returns:
            bool: 如果元素存在返回True，否则返回False
        """
        try:
            # 使用多个选择器尝试定位元素
            selectors = [
                ".image-item.forbid .add-image-box-footer:has-text('添加新图片')",
                ".image-item.forbid .add-image-box",
                "div:has-text('添加新图片'):visible"
            ]
            
            # 依次尝试每个选择器
            for selector in selectors:
                element_count = page.locator(selector).count()
                if element_count > 0 and page.locator(selector).is_visible():
                    print(f"找到添加图片元素，使用选择器: {selector}")
                    return True
            
            print("未找到添加图片元素")
            return False
            
        except Exception as e:
            print(f"检查添加图片元素时出错: {str(e)}")
            traceback.print_exc()
             
   